@using Radzen.Blazor.Rendering
@using System.Text.RegularExpressions
@using Microsoft.JSInterop
@inherits FormComponent<string>

@if (Visible)
{
    <div @ref=@Element style=@Style @onclick=@Toggle @attributes=@Attributes class=@GetCssClass() id=@GetId()>
        @if(Icon != null)
        {
            <i class="rzi">@Icon</i>
        }
        <div class="rz-colorpicker-value" style="background-color: @Color" ></div>
        <button type="button" class="rz-colorpicker-trigger" disabled=@Disabled @onclick:preventDefault><i class="rzi" /></button>
        <Popup @ref=@Popup class="rz-colorpicker-popup" Close=@Close Open=@Open>
            @if (ShowHSV)
            {
                <Draggable class="rz-saturation-picker rz-colorpicker-section" style=@($"background-color: {HSV.ToRGB().ToCSS()}") Drag=@OnSaturationMove>
                    <div class="rz-saturation-white">
                        <div class="rz-saturation-black"></div>
                        <div class="rz-saturation-handle" style=@($"top: {SaturationHandleTop*100}%; left: {SaturationHandleLeft * 100}%")></div>
                    </div>
                </Draggable>
                <div class="rz-colorpicker-preview-area rz-colorpicker-section">
                    <div class="rz-hue-and-alpha">
                        <Draggable class="rz-hue-picker" Drag=@OnHueMove>
                            <div class="rz-hue-handle" style=@($"top: 0; left: {HueHandleLeft * 100}%")></div>
                        </Draggable>
                        <Draggable style=@($"background-image: linear-gradient(to right, {AlphaGradientStart} 0%, {AlphaGradientEnd} 100%)") class="rz-alpha-picker" Drag=@OnAlphaMove>
                            <div class="rz-alpha-handle" style=@($"top: 0; left: {AlphaHandleLeft * 100}%")></div>
                        </Draggable>
                    </div>
                    <div class="rz-colorpicker-preview" style=@($"background-color: {Color}")></div>
                </div>
            }
            @if (ShowRGBA)
            {
                <div class="rz-colorpicker-rgba rz-colorpicker-section" @onmousedown:stopPropagation> 
                    <div class="rz-color-box">
                        <RadzenTextBox Value=@Hex @oninput=@(args => ChangeRGB(args.Value)) />
                        @HexText
                    </div>
                    <div class="rz-color-box">
                        <RadzenNumeric TValue="double" Value=@Red Min="0" Max="255" 
                            @oninput=@(args => ChangeColor(args.Value, (color, value) => color.Red = value)) 
                            Change=@(red => ChangeColor(red, (color, value) => color.Red = value)) 
                        />
                        @RedText
                    </div>
                    <div class="rz-color-box">
                        <RadzenNumeric TValue="double" Value=@Green Min="0" Max="255" 
                            @oninput=@(args => ChangeColor(args.Value, (color, value) => color.Green = value)) 
                            Change=@(green => ChangeColor(green, (color, value) => color.Green = value)) 
                        />
                        @GreenText
                    </div>
                    <div class="rz-color-box">
                        <RadzenNumeric TValue="double" Value=@Blue Min="0" Max="255" 
                            @oninput=@(args => ChangeColor(args.Value, (color, value) => color.Blue = value)) 
                            Change=@(blue => ChangeColor(blue, (color, value) => color.Blue = value)) 
                        />
                        @BlueText
                    </div>
                    <div class="rz-color-box">
                        <RadzenNumeric TValue="double" Value=@Alpha Min="0" Max="100" 
                            @oninput=@(args => ChangeAlpha(args.Value)) 
                            Change=@(alpha => ChangeAlpha(alpha)) 
                        />
                        @AlphaText
                    </div>
                </div>
            }
            @if (ShowColors)
            {
                <div class="rz-colorpicker-colors rz-colorpicker-section">
                    <CascadingValue Value=@this>
                    @if (ChildContent != null)
                    {
                        @ChildContent
                    }
                    else
                    {
                        <RadzenColorPickerItem Value="ff2800" />
                        <RadzenColorPickerItem Value="fe9300" />
                        <RadzenColorPickerItem Value="fefb00" />
                        <RadzenColorPickerItem Value="02f900" />
                        <RadzenColorPickerItem Value="00fdff" />
                        <RadzenColorPickerItem Value="0433ff" />
                        <RadzenColorPickerItem Value="ff40ff" />
                        <RadzenColorPickerItem Value="942292" />
                        <RadzenColorPickerItem Value="aa7942" />
                        <RadzenColorPickerItem Value="ffffff" />
                        <RadzenColorPickerItem Value="000000" />
                        <RadzenColorPickerItem Value="53d5fd" />
                        <RadzenColorPickerItem Value="73a7fe" />
                        <RadzenColorPickerItem Value="874efe" />
                        <RadzenColorPickerItem Value="d357fe" />
                        <RadzenColorPickerItem Value="ed719e" />
                        <RadzenColorPickerItem Value="ff8c82" />
                        <RadzenColorPickerItem Value="ffa57d" />
                        <RadzenColorPickerItem Value="ffc677" />
                        <RadzenColorPickerItem Value="fff995" />
                        <RadzenColorPickerItem Value="ebf38f" />
                        <RadzenColorPickerItem Value="b1dd8c" />
                    }
                    </CascadingValue>
                </div>

            }
            @if(ShowButton)
            {
                <div class="rz-colorpicker-button rz-colorpicker-section">
                    <RadzenButton ButtonStyle="ButtonStyle.Secondary" Click=@OnClick Text=@ButtonText @onclick:preventDefault />
                </div>
            }
        </Popup>
    </div>
}
@code {
    [Parameter]
    public EventCallback Open { get; set; }

    [Parameter]
    public EventCallback Close { get; set; }

    [Parameter]
    public string Icon {get; set;}

    [Parameter]
    public string HexText { get; set; } = "Hex";

    [Parameter]
    public string RedText { get; set; } = "R";

    [Parameter]
    public string GreenText { get; set; } = "G";

    [Parameter]
    public string BlueText { get; set; } = "B";

    [Parameter]
    public string AlphaText { get; set; } = "A";

    [Parameter]
    public string ButtonText { get; set; } = "OK";

    Popup Popup { get; set; }

    string AlphaGradientStart
    {
        get
        {
            var rgb = RGB.Parse(Color);
            rgb.Alpha = 0;
            return rgb.ToCSS();
        }
    }

    string AlphaGradientEnd
    {
        get
        {
            var rgb = RGB.Parse(Color);
            rgb.Alpha = 1;
            return rgb.ToCSS();
        }
    }

    string Hex
    {
        get
        {
            var rgb = RGB.Parse(Color);

            if (rgb != null)
            {
                return rgb.ToHex();
            }

            return String.Empty;
        }
    }


    double Red
    {
        get
        {
            var rgb = RGB.Parse(Color);
            return rgb.Red;
        }
    }

    double Alpha
    {
        get
        {
            return Math.Round(AlphaHandleLeft * 100);
        }
    }

    double Green
    {
        get
        {
            var rgb = RGB.Parse(Color);
            return rgb.Green;
        }
    }

    double Blue
    {
        get
        {
            var rgb = RGB.Parse(Color);
            return rgb.Blue;
        }
    }


    void OnSaturationMove(DraggableEventArgs args)
    {
        SaturationHandleLeft = Math.Clamp((args.ClientX - args.Rect.Left) / args.Rect.Width, 0, 1);
        SaturationHandleTop = Math.Clamp((args.ClientY - args.Rect.Top) / args.Rect.Height, 0, 1);

        var hsv = new HSV { Hue = HSV.Hue, Saturation = SaturationHandleLeft, Value = 1 - SaturationHandleTop, Alpha = AlphaHandleLeft };

        Color = hsv.ToRGB().ToCSS();

        TriggerChange();
    }

    void TriggerChange()
    {
        if (!ShowButton)
        {
            ValueChanged.InvokeAsync(Color);
            Change.InvokeAsync(Color);
        }

        StateHasChanged();
    }

    void ChangeRGB(object value)
    {
        SetValue(value as string);
    }

    void SetValue(string value)
    {
        var rgb = RGB.Parse(value);

        if (rgb != null)
        {
            Color = rgb.ToCSS();
            UpdateColor(rgb);
        }
    }

    internal async Task SelectColor(string value)
    {
        SetValue(value);

        if (!ShowButton)
        {
            await Popup.CloseAsync();
        }
    }

    void UpdateColor(RGB rgb)
    {
        Color = rgb.ToCSS();

        HSV = rgb.ToHSV();

        SaturationHandleLeft = HSV.Saturation;
        SaturationHandleTop = 1 - HSV.Value;
        HueHandleLeft = HSV.Hue;

        TriggerChange();
    }

    void ChangeAlpha(double value)
    {
        if (value >= 0 && value <= 100)
        {
            var rgb = RGB.Parse(Color);
            AlphaHandleLeft = rgb.Alpha = Math.Round(value / 100, 2);

            Color = rgb.ToCSS();

            TriggerChange();
        }
    }

    void ChangeAlpha(object alpha)
    {
        if (Double.TryParse((string)alpha, out var value))
        {
            ChangeAlpha(value);
        }
    }

    void ChangeColor(double value, Action<RGB, double> update)
    {
        if (value >= 0 && value <= 255)
        {
            var rgb = RGB.Parse(Color);

            update(rgb, value);

            UpdateColor(rgb);
        }
    }

    void ChangeColor(object color, Action<RGB, double> update)
    {
        if (Double.TryParse((string)color, out var value))
        {
            ChangeColor(value, update);
        }
    }

    void OnAlphaMove(DraggableEventArgs args)
    {
        AlphaHandleLeft = Math.Round(Math.Clamp((args.ClientX - args.Rect.Left) / args.Rect.Width, 0, 1), 2);

        HSV.Alpha = AlphaHandleLeft;

        var hsv = new HSV { Hue = HSV.Hue, Saturation = SaturationHandleLeft, Value = 1 - SaturationHandleTop, Alpha = AlphaHandleLeft };

        Color = hsv.ToRGB().ToCSS();

        TriggerChange();
    }

    void OnHueMove(DraggableEventArgs args)
    {
        HueHandleLeft = Math.Clamp((args.ClientX - args.Rect.Left) / args.Rect.Width, 0, 1);

        HSV.Hue = HueHandleLeft;
        var hsv = new HSV { Hue = HSV.Hue, Saturation = SaturationHandleLeft, Value = 1 - SaturationHandleTop, Alpha = AlphaHandleLeft };

        Color = hsv.ToRGB().ToCSS();

        TriggerChange();
    }

    async Task OnClick()
    {
        await ValueChanged.InvokeAsync(Color);
        await Change.InvokeAsync(Color);
        await Popup.CloseAsync();
    }

    [Parameter]
    public bool ShowButton { get; set; }

    [Parameter]
    public bool ShowHSV { get; set; } = true;

    [Parameter]
    public bool ShowRGBA { get; set; } = true;

    [Parameter]
    public bool ShowColors { get; set; } = true;

    [Parameter]
    public RenderFragment ChildContent { get; set; }

    double SaturationHandleLeft { get; set; }
    double HueHandleLeft { get; set; }
    double AlphaHandleLeft { get; set; } = 1;
    double SaturationHandleTop { get; set; }

    HSV HSV { get; set; } = new HSV { Hue = 0, Saturation = 1, Value = 1 };

    string Color { get; set; } = "rgb(255, 255, 255)";

    async Task Toggle()
    {
        if (!Disabled)
        {
            await Popup.ToggleAsync(Element);
        }
    }
    protected override string GetComponentCssClass()
    {
        var classList = new List<string>() { "rz-colorpicker" };

        if (Disabled)
        {
            classList.Add("rz-disabled");
        }

        return string.Join(" ", classList);
    }

    protected override void OnInitialized()
    {
        Init();

        base.OnInitialized();
    }

    void Init()
    {
        var value = Value;
        if (String.IsNullOrEmpty(Value))
        {
            value = "rgb(255, 255, 255)";
        }

        if (value != Color)
        {
            Color = value;

            HSV = RGB.Parse(Color).ToHSV();
            SaturationHandleLeft = HSV.Saturation;
            SaturationHandleTop = 1 - HSV.Value;
            HSV.Saturation = 1;
            HSV.Value = 1;

            HueHandleLeft = HSV.Hue;
        }
    }

    public override async Task SetParametersAsync(ParameterView parameters)
    {
        var valueChanged = parameters.DidParameterChange(nameof(Value), Value);

        await base.SetParametersAsync(parameters);

        if (valueChanged)
        {
            Init();
        }
    }
}